<?php
use oxide\plugin\PluginAbstract;
use oxide\http\Context;
use oxide\ui\html;
use oxide\application\View;
use oxide\application\ViewController;
use module\content\model;

define('PLUGIN_RATE_DIR', dirname(__FILE__));

class RatePlugin extends PluginAbstract
{
	protected
		$rate_model = array(),
		$supported_content_type = array();
	
	/**
	 *
	 * @param Context $context 
	 * @notifies 
	 * @listening  CommandInitialize, ModuleContentInfoRenderFooterTermEnd, ContentDefaultListStart, ContentDefaultViewStart,
	 *					ContentDefaultControllerViewQuery, ContentDefaultControllerListQuery
	 */
	public function onInit(Context $context) 
	{	
		$this->register('CommandInitialize');
		
		// content module
		$this->register('ContentDefaultTypeStart', 'rateSubmitUpdate');
		$this->register('ContentDefaultListStart', 'rateSubmitUpdate');
		$this->register('ContentDefaultViewStart', 'rateSubmitUpdate');
		$this->register('ModuleContentInfoRenderFooterTermEnd');
		$this->register('ContentDefaultControllerViewQuery');
		$this->register('ContentDefaultControllerListQuery');
	}
	
	/**
	 * plugin config file checking and setting if not initially set
	 * @param type $event
	 * @param type $sender
	 * @param type $args 
	 */
	public function onCommandInitialize($event, $sender, $args = null)
	{
		$config = $this->getConfig();
		
		// retrieve the config value for rate model from the binaryrate section
		$rate_model = $config->getSectionValue('binaryrate', 'rate_model');
		// check if rate model is not available
		if((bool)$rate_model == false) {
			// if true, save rate model default as no,yes on the plugin config
			$config->setValue('rate_model', 'no,yes', 'binaryrate');
			$config->save();
		} else {
			// if exists, then store the values into array
			$this->rate_model = explode(',', $rate_model);
		}
		
		// retrieve the config value for support content type from the binaryrate section
		$supported_content_type = $config->getSectionValue('binaryrate', 'supported_content_type');
		// check if supported content type is not available
		if((bool)$supported_content_type == false) {
			// if true, save support content type default as ''(meaning access from all) on the plugin config
			$config->setValue('supported_content_type', '', 'binaryrate');
			$config->save();
		} else {
			// if exists, then store the values into array
			$this->supported_content_type = explode(',', $supported_content_type);
		}
	}
	
	
	public function onContentDefaultControllerViewQuery($event, $sender, $args) 
	{
		$query = $args['query'];
		$query->columns(array('binaryrate_rate', 'binaryrate_count'), 'content_extension');
	}
	
	public function onContentDefaultControllerListQuery($event, $sender, $args) 
	{
		$query = $args['query'];
		$query->columns(array('binaryrate_rate', 'binaryrate_count'), 'content_extension');
	}
	
	public function rateSubmitUpdate($event, $sender, $args = null)
	{
		\oxide\application\View::load('_html');
		
		// initialize
		$context = $this->_context;
		$request = $context->getRequest();
		$rate = (float)$request->getQuery('binaryrate');
		$content_pk = (int)$request->getQuery('content');
			
		// check if user is logged in
		$auth = $context->getAuth();
		$user_pk = ($auth->hasIdentity()) ? $auth->getIdentity()->user_pk : null;


		if ($this->validateRate($rate, $content_pk, $user_pk)) {

			// retrieve user rate for the specific content
			$content_user = \module\content\model\ContentUserExtension::findByContent_pkAndUser_pk($content_pk, $user_pk);
			$user_rate = $content_user->binaryrate_userrate;
			$content_extension = \module\content\model\ContentExtension::findByContent_pk($content_pk);

			// save the userrate to content user extension
			$content_user->binaryrate_userrate = $rate;
			$content_user->save();

			//check if user is first time rating
			if ($user_rate == null) {
				// if true, increment the count
				$content_extension->binaryrate_count += 1;
			} 

			else if ($user_rate == $rate)	{ return; }

			else {
				// if user has already made a previous rating for the content
				// check if user currently selected a different rate, 
				// (e.g. user_rate = 0, user clicked = 1 || user_rate = 1, user clicked = 0)

				// if user's previous rate is 1, set rate as -1 to deduct from the initial
				if ($user_rate == 1) { $rate = -1; }
			}

			// save the rate to content extension
			$content_extension->binaryrate_rate += $rate;
			$content_extension->save();

		}
		
	}

	/**
	 * display the rate options at the bottom of the content
	 * @param type $event
	 * @param type $sender
	 * @param type $content 
	 */
	public function onModuleContentInfoRenderFooterTermEnd($event, $sender, $content)
	{	
		// initialize
		\oxide\application\View::load('_html');
		$content_type = $content->content_type;
		// get the module, action, and params value
		$route = $this->getContext()->route;
		$action = $route->action;

		// check if the page is e.g. content/list/{content_type}, or content/view/{content_type}
		// and the rate model is not having empty values, and there must be 2 available values e.g no/yes, false/true
		if (($action == 'view' || $action == 'list') && 
			!empty($this->rate_model) && count($this->rate_model) == 2) {
			
			// if supported content type is filled
			if (!empty($this->supported_content_type)) {

				// check the content type is one of the one from the supported content type list
				// if true, display the rate
				if (in_array($content_type, $this->supported_content_type))
					$this->_renderRateDisplay($content);
				
			} else {
				$this->_renderRateDisplay($content);
			}
		}	
	}
	
	/**
	 * display the rating component
	 * @param int $content_pk
	 * @param int $user_pk 
	 */
	private function _renderRateDisplay($content)
	{
		// intialize user and retrieve the user_pk for rating
		$auth = $this->_context->getAuth();
		$user_pk = ($auth->hasIdentity()) ? (int)$auth->getIdentity()->user_pk : 0;
		
		// initialize
		$rate_count = $content->binaryrate_count;
		$rate_sum = $content->binaryrate_rate;

		$yes_count = (int) $rate_sum;
		$no_count = (int) $rate_count - $rate_sum;
		
		$counts = array($no_count, $yes_count);
		
		_html::tag('dt', "Rate:", "title=binaryrate");
		$el = new html\Element('a');
		foreach ($this->rate_model as $model_rate => $model_text) {
			$el->text($model_text);
			if($user_pk) {
				$href = _url::url(array('binaryrate' => $model_rate, 'content' => $content->content_pk));	
			} else {
				$href = "javascript: alert('Please login')";
			}
			$el->href = $href;
			
			// get the rate count for the current rate model's rate
			$count = $counts[$model_rate];
			if($count) $count_text = " ({$count}) ";
			else $count_text = " (0) ";
			
			// render the available rate option with count
			_html::tag('dd', $el . $count_text);
		}
	}
	
	
	/**
	 * check if value is within the range of keys
	 * @param type $value
	 * @return boolean 
	 */
	public function validateRate($rate, $content_pk, $user_pk)
	{
		// get all keys available for rate model
		$range = $this->rateRange($this->rate_model);
		
		// check if value is within the range
		if (!in_array($rate, $range)) { return false; }
		
		// check if content is not empty and is valid
		if (empty($content_pk)) { return false; }
		
		// check if user pk is not empty and is valid
		if (empty($user_pk)) { return false; }
		
		return true;
	}
	
	/**
	 * get all available keys of rate range
	 * @param array $arr
	 * @return array 
	 */
	protected function rateRange($arr)
	{
		// get all keys available
		$range = array_keys($arr);
		
		if (empty($range)) { return array(); }
		
		return $range;
	}	
}
?>